package guiserver;

import java.awt.Graphics;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

/** Реализует сервер, отрисовывающий изображение клиентского приложения,
 *  а также обрабатывающий пользовательский ввод
 */
public class Server {

    //Порт, на котором слушет сервер
    private final int serverPort = 6666;
    //Время непрерывной прослушки сокетом
    private final int serverSocketTimeout = 100;
    //серверный сокет
    private ServerSocket serverSocket;
    //Статус: подключен/не подключен
    private boolean isConnected;
    //Списочек подключенных клиетов
    private List<SingleClient> clients;
    //Примитив синхронизации
    private Lock lock;
    //поток, в котором работает сервер
    private Thread myThread;

    //Конструктор
    public Server() throws IOException {
        serverSocket = new ServerSocket(serverPort);
        serverSocket.setSoTimeout(serverSocketTimeout);
        isConnected = false;
        clients = new ArrayList<SingleClient>();
        lock = new ReentrantLock();
    }

    //Запуск сервера
    public void Start() {
        //Если уже подключены, ничего не делаем
        if (isConnected)
            return;
        isConnected = true;
        //создаем поток, в котором рабоет сервер
        myThread = new Thread(new Runnable() {
            
            @Override
            public void run() {
                //Пока сервер подключен, крутимся в цикле
                while (isConnected) {
                    try {
                        lock.lock();
                        //Ждем подключения клиента
                        SingleClient client = new SingleClient(serverSocket.accept());
                        //Добавляем клиента
                        clients.add(client);
                        //Запускаем обработку клиента
                        client.Connect();
                    } catch (SocketTimeoutException e) {
                        //Штатный эксепшн - ничего не делаем
                    } catch (IOException ex) {
                        //Ошибка в сокете
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, "Connection error: ", ex);
                    } finally {
                        lock.unlock();
                        try {
                            Thread.sleep(0);
                        } catch (InterruptedException ex) {
                            isConnected = false;
                        }
                    }
                }
            }
        });
        //Запускаем поток
        myThread.start();
    }

    //Остановка сервера
    public void Stop() {
        try {
            try {
                lock.lock();
                isConnected = false;
                try {
                    //Ждем завершения рабочего потока
                    Thread.sleep(serverSocketTimeout);
                } catch (InterruptedException ex) { }
            } finally {
                lock.unlock();
            }
            //отключаем всех клиентов
            for (SingleClient client : clients) {
                client.Disconnect();
            }
            //закрываем сокет
            serverSocket.close();
        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, "Server stop error: ", ex);
        }
    }
}
